// TestHD3DDlg.cpp : implementation file
//

#include "stdafx.h"
#include "TestHD3D.h"
#include "TestHD3DDlg.h"

#include "HD3D.h"
#include <map>

using namespace std;

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	enum { IDD = IDD_ABOUTBOX };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

// Implementation
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CTestHD3DDlg dialog




CTestHD3DDlg::CTestHD3DDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CTestHD3DDlg::IDD, pParent)
	, m_bInit(FALSE)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_dwFrames = 0;
	m_pbBits = NULL;
}

void CTestHD3DDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CTestHD3DDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_WM_LBUTTONUP()
	ON_WM_RBUTTONUP()
	ON_WM_TIMER()
	ON_WM_DESTROY()
END_MESSAGE_MAP()


// CTestHD3DDlg message handlers

BOOL CTestHD3DDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;	
		if (strAboutMenu.LoadString(IDS_ABOUTBOX))
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	CMenu wndMenu;
	if(wndMenu.LoadMenu(MAKEINTRESOURCE(IDM_HOOK)))
	{
		SetMenu(&wndMenu);
		DrawMenuBar();
	}
	
	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
/*
	typedef multimap<int*, int*> MAPDEVICEHOOKER;

	// TODO: Add extra initialization here
	MAPDEVICEHOOKER mi;
	mi.insert(MAPDEVICEHOOKER::value_type((int*)0x122, (int*)3));
	mi.insert(MAPDEVICEHOOKER::value_type((int*)0x124, (int*)4));
	mi.insert(MAPDEVICEHOOKER::value_type((int*)0x122, (int*)4));


	int* p = (int*)0x122;
	MAPDEVICEHOOKER::iterator it;
	pair<MAPDEVICEHOOKER::iterator, MAPDEVICEHOOKER::iterator> its;
	its = mi.equal_range(p);

	int n = mi.count(p);
	DebugInfoTemp(TEXT("map: %x, %x"), &its.first, n);


	for(it = its.first;it!=its.second;)
	{
		mi.erase(it++);
		DebugInfoTemp(TEXT("map: %x, %x"), &its.first, n);
	}

	n = mi.count(p);
*/
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CTestHD3DDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CTestHD3DDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CTestHD3DDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}


void CTestHD3DDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	if(m_bInit) return;

	m_dwWidth = m_dwHeight = 0;
	m_pbBits = new BYTE[1280*1024*4];

	m_bInit = InitHD3D();
	if(m_bInit)
	{
		m_hCaptor = CreateCaptor("\\\\.\\DISPLAY1");
		//m_hCaptor = CreateCaptor("\0\\\.\\DISPLAY2");
		if(m_hCaptor)
		{
			SetTimer(1, 10-0, NULL);
		}
	}

	if(!(m_bInit&&m_hCaptor))
		MessageBox(TEXT("Error to create Captor."));

	CDialog::OnLButtonUp(nFlags, point);
}

void CTestHD3DDlg::OnRButtonUp(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	StopCapture();
	CDialog::OnRButtonUp(nFlags, point);
}

void CTestHD3DDlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: Add your message handler code here and/or call default
	static DWORD s_dwTick = GetTickCount();

	D3DFORMAT d3dfmt;
	DWORD dwWidth;
	DWORD dwHeight;
	INT iPitch;
	BYTE* pbBits;
	RGNDATA* prd;
	if (GetCaptorChange(m_hCaptor, &d3dfmt, &dwWidth, &dwHeight, &iPitch, (void**)&pbBits, &prd))
	{
		DebugInfoTemp(TEXT("Get Captor Change: %d (%d, %d) %d %08X"), d3dfmt, dwWidth, dwHeight, iPitch, *(DWORD*)(pbBits + (iPitch * dwHeight + iPitch) / 2));
		
/*		if (m_dwWidth != dwWidth || m_dwHeight != dwHeight || m_d3dfmt != d3dfmt)
		{
			if (m_pbBits)
				delete [] m_pbBits;
			m_dwWidth = dwWidth;
			m_dwHeight = dwHeight;
			m_d3dfmt = d3dfmt;
			m_pbBits = new BYTE[iPitch * dwHeight];
		}
*/
		RECT* prc = (RECT*)prd->Buffer;
		for (DWORD i = 0; i < prd->rdh.nCount; i++)
		{
			DebugInfoTemp(TEXT("Region Rect:(%d)(%d, %d - %d, %d)"),i, prc->left, prc->top, prc->right, prc->bottom);
			BYTE* pb0 = pbBits + iPitch * prc->top + 4 * prc->left;
			BYTE* pb1 = m_pbBits + iPitch * prc->top + 4 * prc->left;
			DWORD dwLen = 4 * (prc->right - prc->left);
			for (int y = prc->top; y < prc->bottom; y++)
			{
				memcpy(pb1, pb0, dwLen);
				pb0 += iPitch;
				pb1 += iPitch;
			}
			prc++;
		}

//		HRGN hrgn = ExtCreateRegion(NULL, prd->rdh.dwSize + prd->rdh.nRgnSize, prd);
		CleanCaptorChange(m_hCaptor);

//		RECT rc;
//		GetClientRect(&rc);
		BITMAPINFO bi = {};
		bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
		bi.bmiHeader.biWidth = dwWidth;
		bi.bmiHeader.biHeight = -(LONG)(dwHeight);
		bi.bmiHeader.biPlanes = 1;
		bi.bmiHeader.biBitCount = 32;
	
		HDC hdc = ::GetDC(m_hWnd);

//		SetStretchBltMode(hdc, HALFTONE);

		StretchDIBits(hdc, 0, 0, dwWidth, dwHeight, 0, 0, dwWidth, dwHeight, 
			m_pbBits, &bi, DIB_RGB_COLORS, SRCCOPY);

		m_dwFrames++;

		DWORD dwFramsPerSec = m_dwFrames/((GetTickCount()-s_dwTick)/1000+1);

		TCHAR tchFrames[64];
		_stprintf_s(tchFrames, TEXT("Frame Per Sec: %d"), dwFramsPerSec);

		RECT rcDraw = {20,20,220, 100};
		DrawText(hdc, tchFrames, -1, &rcDraw, DT_CENTER);
		//BitBlt(hdc, 0, 0, dwWidth, dwHeight, hdcScr, 0, 0, SRCCOPY);

		DebugInfoTemp(TEXT("Finish draw frame"));

		::ReleaseDC(m_hWnd, hdc);
//		DeleteObject(hrgn);
	}

	CDialog::OnTimer(nIDEvent);
}

void CTestHD3DDlg::OnDestroy()
{
	StopCapture();
	CDialog::OnDestroy();

	// TODO: Add your message handler code here
}

BOOL CTestHD3DDlg::StopCapture(void)
{
	KillTimer(1);
	FinHD3D();

	//DestroyCaptor(m_hCaptor);
	if (m_pbBits)
	{
		delete [] m_pbBits;
		m_pbBits = NULL;
	}

	m_bInit = FALSE;

	return TRUE;
}
